﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="DiagonalMatrixExtensions.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.DecimalExtensions
{
    #region Usings

    using System;
    using System.Diagnostics.CodeAnalysis;

    #endregion

    /// <summary>
    ///     Provides extension methods for <see cref="DiagonalMatrix{T}"/> with <see cref="decimal"/> type parameter.
    /// </summary>
    public static class DiagonalMatrixExtensions
    {
        #region Methods

        #region public

        /// <summary>
        ///     Adds the specified factor to all elements of the matrix.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix whose elements should be added.
        /// </param>
        /// <param name="factor">
        ///     The factor to add.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see langword="null"/>.
        /// </exception>
        public static void Add(this DiagonalMatrix<decimal> matrix, decimal factor)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

#endif

            var values = matrix.Values;
            var elementsCount = matrix.RowsCount;

            for (var elementIndex = 0; elementIndex < elementsCount; elementIndex++)
            {
                values[elementIndex] += factor;
            }
        }

        /// <summary>
        ///     Adds the second matrix to the first matrix.
        /// </summary>
        /// <param name="augend">
        ///     The augend matrix.
        /// </param>
        /// <param name="addend">
        ///     The addend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="augend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="addend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.RowsCount, <paramref name="addend"/>.RowsCount).
        ///     The number of columns of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.ColumnsCount, <paramref name="addend"/>.ColumnsCount).
        /// </remarks>
        public static void Add(this DiagonalMatrix<decimal> augend, DiagonalMatrix<decimal> addend)
        {
#if SAFE

            if (augend == null)
            {
                throw new ArgumentNullException("augend");
            }

            if (addend == null)
            {
                throw new ArgumentNullException("addend");
            }

#endif

            var augendValues = augend.Values;
            var addendValues = addend.Values;

            var elementsCountToAdd = Math.Min(augend.RowsCount, addend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToAdd; elementIndex++)
            {
                augendValues[elementIndex] += addendValues[elementIndex];
            }
        }

        /// <summary>
        ///     Adds the second matrix to the first matrix multiplied by the factor.
        /// </summary>
        /// <param name="augend">
        ///     The augend matrix.
        /// </param>
        /// <param name="augendFactor">
        ///     The factor of the augend matrix.
        /// </param>
        /// <param name="addend">
        ///     The addend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="augend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="addend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.RowsCount, <paramref name="addend"/>.RowsCount).
        ///     The number of columns of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.ColumnsCount, <paramref name="addend"/>.ColumnsCount).
        /// </remarks>
        public static void Add(this DiagonalMatrix<decimal> augend, decimal augendFactor, DiagonalMatrix<decimal> addend)
        {
#if SAFE

            if (augend == null)
            {
                throw new ArgumentNullException("augend");
            }

            if (addend == null)
            {
                throw new ArgumentNullException("addend");
            }

#endif

            var augendValues = augend.Values;
            var addendValues = addend.Values;

            var elementsCountToAdd = Math.Min(augend.RowsCount, addend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToAdd; elementIndex++)
            {
                augendValues[elementIndex] = (augendFactor * augendValues[elementIndex]) + addendValues[elementIndex];
            }
        }

        /// <summary>
        ///     Adds the second matrix multiplied by the factor to the first matrix.
        /// </summary>
        /// <param name="augend">
        ///     The augend matrix.
        /// </param>
        /// <param name="addend">
        ///     The addend matrix.
        /// </param>
        /// <param name="addendFactor">
        ///     The factor of the addend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="augend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="addend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.RowsCount, <paramref name="addend"/>.RowsCount).
        ///     The number of columns of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.ColumnsCount, <paramref name="addend"/>.ColumnsCount).
        /// </remarks>
        public static void Add(this DiagonalMatrix<decimal> augend, DiagonalMatrix<decimal> addend, decimal addendFactor)
        {
#if SAFE

            if (augend == null)
            {
                throw new ArgumentNullException("augend");
            }

            if (addend == null)
            {
                throw new ArgumentNullException("addend");
            }

#endif

            var augendValues = augend.Values;
            var addendValues = addend.Values;

            var elementsCountToAdd = Math.Min(augend.RowsCount, addend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToAdd; elementIndex++)
            {
                augendValues[elementIndex] += addendFactor * addendValues[elementIndex];
            }
        }

        /// <summary>
        ///     Adds the second matrix multiplied by the second factor to the first matrix multiplied by the first factor.
        /// </summary>
        /// <param name="augend">
        ///     The augend matrix.
        /// </param>
        /// <param name="augendFactor">
        ///     The factor of the augend matrix.
        /// </param>
        /// <param name="addend">
        ///     The addend matrix.
        /// </param>
        /// <param name="addendFactor">
        ///     The factor of the addend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="augend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="addend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.RowsCount, <paramref name="addend"/>.RowsCount).
        ///     The number of columns of <paramref name="addend"/> to add to <paramref name="augend"/> is determined as
        ///     min(<paramref name="augend"/>.ColumnsCount, <paramref name="addend"/>.ColumnsCount).
        /// </remarks>
        public static void Add(
            this DiagonalMatrix<decimal> augend, decimal augendFactor, DiagonalMatrix<decimal> addend, decimal addendFactor)
        {
#if SAFE

            if (augend == null)
            {
                throw new ArgumentNullException("augend");
            }

            if (addend == null)
            {
                throw new ArgumentNullException("addend");
            }

#endif

            var augendValues = augend.Values;
            var addendValues = addend.Values;

            var elementsCountToAdd = Math.Min(augend.RowsCount, addend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToAdd; elementIndex++)
            {
                augendValues[elementIndex] =
                    (augendFactor * augendValues[elementIndex]) + (addendFactor * addendValues[elementIndex]);
            }
        }

        /// <summary>
        ///     Decomposes the matrix by diagonal decomposition.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix to decompose.
        /// </param>
        /// <returns>
        ///     The decomposition matrix.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see langword="null"/>.
        /// </exception>
        /// <remarks>
        ///     The method does nothing.
        /// </remarks>
        [SuppressMessage(
            "Microsoft.Design",
            "CA1011:ConsiderPassingBaseTypesAsParameters",
            Justification = "This methods is intended to use with this specific type of matrix.")]
        public static DecompositionMatrix<decimal> DecomposeByDiagonal(this DiagonalMatrix<decimal> matrix)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

#endif

            return new DecompositionMatrix<decimal>(matrix, DecompositionAlgorithm.Diagonal);
        }

        /// <summary>
        ///     Multiplies all elements of the matrix by the specified factor.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix whose elements should be multiplied.
        /// </param>
        /// <param name="factor">
        ///     The factor to multiply.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see langword="null"/>.
        /// </exception>
        public static void Multiply(this DiagonalMatrix<decimal> matrix, decimal factor)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

#endif

            var values = matrix.Values;
            var elementsCount = matrix.RowsCount;

            for (var elementIndex = 0; elementIndex < elementsCount; elementIndex++)
            {
                values[elementIndex] *= factor;
            }
        }

        /// <summary>
        ///     Multiplies the matrix by the dense vector and stores the result in the another vector.
        /// </summary>
        /// <param name="multiplicand">
        ///     The multiplicand matrix.
        /// </param>
        /// <param name="multiplier">
        ///     The multiplier vector.
        /// </param>
        /// <param name="result">
        ///     The vector to store the result.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="multiplicand"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="multiplier"/> is <see langword="null"/>.
        ///     </para>
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="result"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="multiplicand"/> to multiply is determined as
        ///     min(<paramref name="multiplicand"/>.RowsCount, <paramref name="result"/>.Length).
        ///     The number of columns of <paramref name="multiplicand"/> to multiply is determined as
        ///     min(<paramref name="multiplicand"/>.ColumnsCount, <paramref name="multiplier"/>.Length).
        /// </remarks>
        public static void Multiply(
            this DiagonalMatrix<decimal> multiplicand, DenseVector<decimal> multiplier, DenseVector<decimal> result)
        {
#if SAFE

            if (multiplicand == null)
            {
                throw new ArgumentNullException("multiplicand");
            }

            if (multiplier == null)
            {
                throw new ArgumentNullException("multiplier");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

#endif

            var multiplicandValues = multiplicand.Values;
            var multiplierValues = multiplier.Values;
            var resultValues = result.Values;

            result.Clear();

            var rowsCountToMultiply = Math.Min(multiplicand.RowsCount, Math.Min(multiplier.Length, result.Length));

            for (var rowIndex = 0; rowIndex < rowsCountToMultiply; rowIndex++)
            {
                resultValues[rowIndex] = multiplicandValues[rowIndex] * multiplierValues[rowIndex];
            }
        }

        /// <summary>
        ///     Solves a system of linear algebraic equations with the specified matrix and the right-hand part and
        ///     stores the result in the right-hand part vector.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix of system.
        /// </param>
        /// <param name="rightHandPart">
        ///     The right-hand part vector as input and the result vector as output.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see lagnword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="rightHandPart"/> is <see lagnword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The size of system to solve is determined as minimal value from size of <paramref name="matrix"/> and
        ///     length of <paramref name="rightHandPart"/>.
        /// </remarks>
        public static void SolveWithDiagonal(this DiagonalMatrix<decimal> matrix, DenseVector<decimal> rightHandPart)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (rightHandPart == null)
            {
                throw new ArgumentNullException("rightHandPart");
            }

#endif

            var matrixValues = matrix.Values;
            var resultValues = rightHandPart.Values;

            var rowsCount = Math.Min(matrix.RowsCount, rightHandPart.Length);
            for (var rowIndex = 0; rowIndex < rowsCount; rowIndex++)
            {
                resultValues[rowIndex] /= matrixValues[rowIndex];
            }
        }

        /// <summary>
        ///     Solves a system of linear algebraic equations with the specified matrix and the right-hand part and
        ///     stores the result in the right-hand part vector.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix of system.
        /// </param>
        /// <param name="rightHandPart">
        ///     The right-hand part vector as input and the result vector as output.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see lagnword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="rightHandPart"/> is <see lagnword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The size of system to solve is determined as minimal value from columns count of <paramref name="matrix"/> and
        ///     length of <paramref name="rightHandPart"/>.
        /// </remarks>
        public static void SolveWithHighTriangle(this DiagonalMatrix<decimal> matrix, DenseVector<decimal> rightHandPart)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (rightHandPart == null)
            {
                throw new ArgumentNullException("rightHandPart");
            }

#endif
        }

        /// <summary>
        ///     Solves a system of linear algebraic equations with the specified matrix and the right-hand part and
        ///     stores the result in the right-hand part vector.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix of system.
        /// </param>
        /// <param name="rightHandPart">
        ///     The right-hand part vector as input and the result vector as output.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see lagnword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="rightHandPart"/> is <see lagnword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The size of system to solve is determined as minimal value from columns count of <paramref name="matrix"/> and
        ///     length of <paramref name="rightHandPart"/>.
        /// </remarks>
        public static void SolveWithHighTriangleAndDiagonal(
            this DiagonalMatrix<decimal> matrix, DenseVector<decimal> rightHandPart)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (rightHandPart == null)
            {
                throw new ArgumentNullException("rightHandPart");
            }

#endif

            var matrixValues = matrix.Values;
            var resultValues = rightHandPart.Values;

            var columnsCount = Math.Min(matrix.RowsCount, rightHandPart.Length);
            for (var columnIndex = 0; columnIndex < columnsCount; columnIndex++)
            {
                resultValues[columnIndex] /= matrixValues[columnIndex];
            }
        }

        /// <summary>
        ///     Solves a system of linear algebraic equations with the specified matrix and the right-hand part and
        ///     stores the result in the right-hand part vector.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix of system.
        /// </param>
        /// <param name="rightHandPart">
        ///     The right-hand part vector as input and the result vector as output.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see lagnword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="rightHandPart"/> is <see lagnword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The size of system to solve is determined as minimal value from rows count of <paramref name="matrix"/> and
        ///     length of <paramref name="rightHandPart"/>.
        /// </remarks>
        public static void SolveWithLowTriangle(this DiagonalMatrix<decimal> matrix, DenseVector<decimal> rightHandPart)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (rightHandPart == null)
            {
                throw new ArgumentNullException("rightHandPart");
            }

#endif
        }

        /// <summary>
        ///     Solves a system of linear algebraic equations with the specified matrix and the right-hand part and
        ///     stores the result in the right-hand part vector.
        /// </summary>
        /// <param name="matrix">
        ///     The matrix of system.
        /// </param>
        /// <param name="rightHandPart">
        ///     The right-hand part vector as input and the result vector as output.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="matrix"/> is <see lagnword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="rightHandPart"/> is <see lagnword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The size of system to solve is determined as minimal value from rows count of <paramref name="matrix"/> and
        ///     length of <paramref name="rightHandPart"/>.
        /// </remarks>
        public static void SolveWithLowTriangleAndDiagonal(
            this DiagonalMatrix<decimal> matrix, DenseVector<decimal> rightHandPart)
        {
#if SAFE

            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (rightHandPart == null)
            {
                throw new ArgumentNullException("rightHandPart");
            }

#endif

            var matrixValues = matrix.Values;
            var resultValues = rightHandPart.Values;

            var rowsCount = Math.Min(matrix.RowsCount, rightHandPart.Length);
            for (var rowIndex = 0; rowIndex < rowsCount; rowIndex++)
            {
                resultValues[rowIndex] /= matrixValues[rowIndex];
            }
        }

        /// <summary>
        ///     Subtracts the second matrix from the first matrix.
        /// </summary>
        /// <param name="minuend">
        ///     The minuend matrix.
        /// </param>
        /// <param name="subtrahend">
        ///     The subtrahend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="minuend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="subtrahend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.RowsCount, <paramref name="subtrahend"/>.RowsCount).
        ///     The number of columns of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.ColumnsCount, <paramref name="subtrahend"/>.ColumnsCount).
        /// </remarks>
        public static void Subtract(this DiagonalMatrix<decimal> minuend, DiagonalMatrix<decimal> subtrahend)
        {
#if SAFE

            if (minuend == null)
            {
                throw new ArgumentNullException("minuend");
            }

            if (subtrahend == null)
            {
                throw new ArgumentNullException("subtrahend");
            }

#endif

            var minuendValues = minuend.Values;
            var subtrahendValues = subtrahend.Values;

            var elementsCountToSubtract = Math.Min(minuend.RowsCount, subtrahend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToSubtract; elementIndex++)
            {
                minuendValues[elementIndex] -= subtrahendValues[elementIndex];
            }
        }

        /// <summary>
        ///     Subtracts the second matrix from the first matrix multiplied by the factor.
        /// </summary>
        /// <param name="minuend">
        ///     The minuend matrix.
        /// </param>
        /// <param name="minuendFactor">
        ///     The factor of the minuend matrix.
        /// </param>
        /// <param name="subtrahend">
        ///     The subtrahend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="minuend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="subtrahend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.RowsCount, <paramref name="subtrahend"/>.RowsCount).
        ///     The number of columns of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.ColumnsCount, <paramref name="subtrahend"/>.ColumnsCount).
        /// </remarks>
        public static void Subtract(
            this DiagonalMatrix<decimal> minuend, decimal minuendFactor, DiagonalMatrix<decimal> subtrahend)
        {
#if SAFE

            if (minuend == null)
            {
                throw new ArgumentNullException("minuend");
            }

            if (subtrahend == null)
            {
                throw new ArgumentNullException("subtrahend");
            }

#endif

            var minuendValues = minuend.Values;
            var subtrahendValues = subtrahend.Values;

            var elementsCountToSubtract = Math.Min(minuend.RowsCount, subtrahend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToSubtract; elementIndex++)
            {
                minuendValues[elementIndex] = (minuendFactor * minuendValues[elementIndex]) - subtrahendValues[elementIndex];
            }
        }

        /// <summary>
        ///     Subtracts the second matrix multiplied by the factor from the first matrix.
        /// </summary>
        /// <param name="minuend">
        ///     The minuend matrix.
        /// </param>
        /// <param name="subtrahend">
        ///     The subtrahend matrix.
        /// </param>
        /// <param name="subtrahendFactor">
        ///     The factor of the subtrahend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="minuend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="subtrahend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.RowsCount, <paramref name="subtrahend"/>.RowsCount).
        ///     The number of columns of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.ColumnsCount, <paramref name="subtrahend"/>.ColumnsCount).
        /// </remarks>
        public static void Subtract(
            this DiagonalMatrix<decimal> minuend, DiagonalMatrix<decimal> subtrahend, decimal subtrahendFactor)
        {
#if SAFE

            if (minuend == null)
            {
                throw new ArgumentNullException("minuend");
            }

            if (subtrahend == null)
            {
                throw new ArgumentNullException("subtrahend");
            }

#endif

            var minuendValues = minuend.Values;
            var subtrahendValues = subtrahend.Values;

            var elementsCountToSubtract = Math.Min(minuend.RowsCount, subtrahend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToSubtract; elementIndex++)
            {
                minuendValues[elementIndex] -= subtrahendFactor * subtrahendValues[elementIndex];
            }
        }

        /// <summary>
        ///     Subtracts the second matrix multiplied by the second factor from the first matrix multiplied by the first factor.
        /// </summary>
        /// <param name="minuend">
        ///     The minuend matrix.
        /// </param>
        /// <param name="minuendFactor">
        ///     The factor of the minuend matrix.
        /// </param>
        /// <param name="subtrahend">
        ///     The subtrahend matrix.
        /// </param>
        /// <param name="subtrahendFactor">
        ///     The factor of the subtrahend matrix.
        /// </param>
        /// <exception cref="ArgumentNullException">
        ///     <paramref name="minuend"/> is <see langword="null"/>.
        ///     <para>
        ///         --or--
        ///     </para>
        ///     <para>
        ///         <paramref name="subtrahend"/> is <see langword="null"/>.
        ///     </para>
        /// </exception>
        /// <remarks>
        ///     The number of rows of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.RowsCount, <paramref name="subtrahend"/>.RowsCount).
        ///     The number of columns of <paramref name="subtrahend"/> to subtract from <paramref name="minuend"/>
        ///     is determined as min(<paramref name="minuend"/>.ColumnsCount, <paramref name="subtrahend"/>.ColumnsCount).
        /// </remarks>
        public static void Subtract(
            this DiagonalMatrix<decimal> minuend,
            decimal minuendFactor,
            DiagonalMatrix<decimal> subtrahend,
            decimal subtrahendFactor)
        {
#if SAFE

            if (minuend == null)
            {
                throw new ArgumentNullException("minuend");
            }

            if (subtrahend == null)
            {
                throw new ArgumentNullException("subtrahend");
            }

#endif

            var minuendValues = minuend.Values;
            var subtrahendValues = subtrahend.Values;

            var elementsCountToSubtract = Math.Min(minuend.RowsCount, subtrahend.RowsCount);

            for (var elementIndex = 0; elementIndex < elementsCountToSubtract; elementIndex++)
            {
                minuendValues[elementIndex] =
                    (minuendFactor * minuendValues[elementIndex]) - (subtrahendFactor * subtrahendValues[elementIndex]);
            }
        }

        #endregion

        #endregion
    }
}